/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.server.main;

import com.core.log.Debug;
import com.core.log.LogDef;
import com.core.log.LogWriter;
import com.core.utils.ConfigReaderSlave;
import com.core.utils.Def;
import com.core.utils.JarLoader;
import com.server.database.DataEngine;
import com.server.game.GameManager;
import com.server.pool.ThreadPool;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.Hashtable;
import process.ICardCharger;

/**
 *
 * @author daz
 */
public class ServerManager {

    private ServerSocket serverSocket;
    private Hashtable usersMap;
    private int slavePort;
    private int delayTime;
    private String pathFileLog;
    private DataEngine dataEngine;
    private GameManager gameManager;
    private IdContainer idContainer;
    private boolean isRunning;
    private ChargeMoneySmS chargeMoney;
    private LogWriter objWriter = null;
    private String _csModuleName = "poker";
    private byte _nLogLevel = LogDef.LOG_LEVEL.LOG_INFO;
    private ThreadPool threadPool;
    private int poolSize;
    private JarLoader jarLoader;
    private ICardCharger cardCharger;

    public ServerManager() throws Exception {
        loadConfig();
        initializeGame();
        initLogger();
        isRunning = true;
    }

    public ICardCharger getCardCharger() {
        return cardCharger;
    }

    private void initializeGame() {
        usersMap = new Hashtable();
        idContainer = new IdContainer();
        gameManager = new GameManager();
//        chargeMoney = new ChargeMoneySmS(gameManager);
//        chargeMoney.start();
        //create data engine 
        dataEngine = DataEngine.getInstance();
        dataEngine.connectToDabatabase();
        System.out.println("test :" + dataEngine.testConnection());
        dataEngine.resetUserIsplay();
    }

    private void loadConfig() throws IOException {
        ConfigReaderSlave config = new ConfigReaderSlave();
        pathFileLog = config.getValue(Def.LOGFILE_LOCATION);
        slavePort = Integer.valueOf(config.getValue(Def.STR_SLAVE_PORT));
        String cardChargerPath = config.getValue(Def.STR_CARD_CHARGER);
        loadCardCharger(cardChargerPath);
        serverSocket = new ServerSocket(slavePort);
    }

    private void loadCardCharger(String path) {
//        try {
        try {
            URL urls[] = {};
            jarLoader = new JarLoader(urls);
            jarLoader.addFile(path + File.separator + "CardCharger.jar");
            cardCharger = (ICardCharger) jarLoader.loadClass("process.Charger").newInstance();
            cardCharger.init(path);
//            cardCharger.userCard("12345678912", "123456789", "10000", "VNP");
        } catch (InstantiationException ex) {
        } catch (IllegalAccessException ex) {
        } catch (ClassNotFoundException ex) {
        } catch (MalformedURLException ex) {
        }


    }

    public void acceptConnection() {
        while (isRunning) {
            try {
                Socket clientSocket = serverSocket.accept();
                clientSocket.setTcpNoDelay(true);
                long userId = idContainer.newId();
//                logUserStatus("new connection " + userId, LogDef.LOG_LEVEL.LOG_INFO);
                ClientManager client = new ClientManager(this, clientSocket, userId);
                client.start();
                usersMap.put(userId, client);
                Debug.d("thread.count=" + Thread.getAllStackTraces().size());
                Runtime.getRuntime().gc();
//                printMemory();
            } catch (Exception ex) {
                try {
                    Thread.sleep(delayTime);
                } catch (InterruptedException e) {
                }
            }
        }
    }

    private void printMemory() {
//        System.out.println("Max memory    :" + (Runtime.getRuntime().maxMemory() >> 20));
//        System.out.println("--------------------------------------------------------------");
        System.out.println("thread.count=" + Thread.getAllStackTraces().size());
//        System.out.println("Free memory   :" + (Runtime.getRuntime().freeMemory() >> 20));
//        System.out.println("Total memmory :" + (Runtime.getRuntime().totalMemory() >> 20));
//        System.out.println("Use memmory :" + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20));
        Runtime.getRuntime().gc();

    }

//    public synchronized void logUserStatus(String logMsg, byte nLevel) {
//        if (objWriter != null) {
//            objWriter.writeLog(logMsg, nLevel);
//        } else {
//        }
//    }
//    public synchronized void logError(String logMsg, Throwable throwable) {
//        if (objWriter != null) {
//            objWriter.writeError(logMsg, throwable);
//        } else {
//        }
//    }
    private void initLogger() {
        //Init logger
        objWriter = new LogWriter(_csModuleName, _nLogLevel);

        objWriter.setFileLogInfo(true, pathFileLog, _csModuleName,
                LogDef.FILE.CHANGE_ON_SZIE, //Change file when maximum size reached
                LogDef.FILE.MAX_FILE_SIZE / 10, //1M
                LogDef.FILE.MAX_FILE_BACKUP_INDEX,// 1000 file per day
                false //flush immediately
                );
        objWriter.setSysLogInfo(true, "localhost", 513);
        objWriter.setConsoleInfo(true);

        objWriter.open();
    }

    public Socket getClientSocket(long userId) {
        ClientManager client = (ClientManager) this.usersMap.get(userId);
        if (client != null) {
            return client.getClientSocket();
        }
        return null;
    }

    public void removeClient(ClientManager client, long userId) {
        this.usersMap.remove(userId);
        Runtime.getRuntime().gc();
    }

    public GameManager getGameManager() {
        return gameManager;
    }

    public ClientManager getClient(long userId) {
        ClientManager client = (ClientManager) this.usersMap.get(userId);
        if (client != null) {
            return client;
        }
        return null;
    }
}
